package malha;

import java.util.LinkedList;

import malhaFerroviaria.Ferrovia;
import controle.CControle;

/**
 * Um trecho do trilho por onde composicoes transitam.
 *
 */
public class CTrecho extends CElementoTrilho{
	
	private int nComposicoes = 0;
	LinkedList<CComposicao> composicoes = new LinkedList<CComposicao>();
		
	/**
	 * Construtor com ID
	 */
	public CTrecho(String id) {
		super(id);	
	}
	
	/**
	 * Quantidade de composicoes transitando neste CTrecho
	 * 
	 * @return um inteiro que representa a quantidade de composicoes
	 * transitando neste CTrecho
	 */
	public int getnComposicoes() {
		return nComposicoes;
	}

	
	/**
	 * Uma fila de CComposicoes que transitam neste CTrecho
	 * @return Uma fila de CComposicoes que transitam neste CTrecho
	 */
	public LinkedList<CComposicao> getComposicoes() {
		return composicoes;
	}

	
	/**
	 * Adiciona uma CComposicao na fila de CComposicoes de um trecho
	 * 
	 * @param composicao Uma CComposicao a ser adicionada neste Trecho 
	 * @param inicializandoMalha Se verdadeiro forca a insercao evitando verificar
	 * algumas pre-condicoes
	 * 
	 * @pre O elemento de trilho de onde veio a composicao e uma CChave (Pre1)
	 * @pre <code>composicao</code> deve ter vindo de uma chave ligada ao trecho (Pre2)
	 * @pre A chave de onde veio a composicao deve possui-la (Pre3)
	 * @pre O sentido de <code>composicao</code> deve ser o mesmo das outras composicoes 
	 * do trecho, se hover alguma (Pre4)
	 * 
	 * @inv A ordem das outras composicoes deste trecho nao muda
	 * @inv O sentido das composicoes neste trecho nao muda
	 * 
	 * @post A chave de onde veio a composicao nao deve mais possui-la (Post1)
	 * @post <code>composicao</code> agora pertence a fila de CComposicoes deste
	 * trecho e eh a ultima da fila (Post2)
	 * @post nComposicoes incrementado de um elemnto (Post3)

	 */
	public void adicionarComposicao(CComposicao composicao, boolean inicializandoMalha) {
		CChave chaveAnterior = null;
		
		if(!inicializandoMalha)
		{
			chaveAnterior = (CChave) composicao.getTrechoChaveAtual();
		}
		
		boolean sentidoDasComposicoes;
		int nComposicoesInicial = composicoes.size();

		/*(Pre1)*/
		assert(inicializandoMalha || chaveAnterior != null);
		
		/*(Pre2)*/
		assert(	inicializandoMalha || 
				chaveAnterior == getElementoAtualA() || 
				chaveAnterior == getElementoAtualB() );
		
		/*(Pre3)*/
		assert(inicializandoMalha || chaveAnterior.getComposicaoPassando() == composicao);
		
		/*(Pre4)*/
		if(composicoes.size() > 0) 
		{
			sentidoDasComposicoes = composicoes.peekLast().isMovendoAParaB();
			assert(sentidoDasComposicoes == composicao.isMovendoAParaB());
		}
		
		/*<IMPLEMENTACAO>*/
		
		composicoes.add(composicao);
		//assert(composicoes.add(composicao));
		this.nComposicoes = composicoes.size();
		if(chaveAnterior != null)
		{
			chaveAnterior.removeComposicao();
		}
		composicao.setTrechoChaveAtual(this);
		
		/*</IMPLEMENTACAO>*/
		
		/*(Post1)*/
		assert(inicializandoMalha || chaveAnterior.getComposicaoPassando() != composicao);
		
		/*Post2*/
		assert(composicao.getTrechoChaveAtual() == this && composicoes.peekLast() == composicao);
		
		/*Post3*/
		assert(nComposicoesInicial + 1 == composicoes.size());
	}
	
	
	/** Seta a chave ligada no lado A deste trecho
	 *	@param novoElemento Uma chave que conectara o lado A do trecho a outro trecho
	 *	@param inicializandoMalha Se for verdadeiro, forca a mudanca do atributo para fins 
	 *	de inicializacao	
	 *	@pre o parametro passado deve ser uma CChave (Pre 1)
	 *	@pre A chave desve etar sendo inicializada ou este trecho deve pertencer ao 
	 *	conjunto de  trechos da chave (Pre 2)
	 *	@post A chave ligada no lado A deste trecho eh a chave passada (Pos 1)
	 */
	@Override
	public void setElementoAtualA(CElementoTrilho novoElemento, boolean inicializandoMalha) {
		
		CChave chave = (CChave) novoElemento;
		
		/*Pre 1*/
		//assert(chave != null);
		
		/*Pre 2*/
		assert(inicializandoMalha || chave.getTrechosA().contains(this) || chave.getTrechosB().contains(this));
		
		/*<IMPLEMENTACAO>*/
		elementoAtualA = novoElemento;
		/*</IMPLEMENTACAO>*/
		
		/*(Pos 1)*/
		assert(elementoAtualA == novoElemento);
	}

	/** Seta a chave ligada no lado A deste trecho
	 *	@param novoElemento Uma chave que conectara o lado B do trecho a outro trecho
	 *	@param inicializandoMalha Se for verdadeiro, forca a mudanca do atributo para fins 
	 *	de inicializacao	
	 *	@pre o parametro passado deve ser uma CChave (Pre 1)
	 *	@pre A chave desve etar sendo inicializada ou este trecho deve pertencer ao 
	 *	conjunto de  trechos da chave (Pre 2)
	 *	@post A chave ligada no lado B deste trecho eh a chave passada (Pos 1)
	 */
	@Override
	public void setElementoAtualB(CElementoTrilho novoElemento, boolean inicializandoMalha) {
		elementoAtualB = novoElemento;
		
		CChave chave = (CChave) novoElemento;
		
		/*Pre 1*/
		//assert(chave != null);
		
		/*Pre 2*/
		assert(inicializandoMalha || chave.getTrechosA().contains(this) || chave.getTrechosB().contains(this));
		
		/*<IMPLEMENTACAO>*/
		elementoAtualB = novoElemento;
		/*</IMPLEMENTACAO>*/
		
		/*(Pos 1)*/
		assert(elementoAtualB == novoElemento);
		
	}

	/**
	 * 
	 * @param nComposicoes Quantidade de composicoes que este
	 * trecho possui
	 * @post A quantidade de composicoes deste trecho eh setada (Pos 1)
	 */
	public void setnComposicoes(int nComposicoes) {
		
		
		this.nComposicoes = nComposicoes;
		
		/*Pos 1*/
		assert(this.nComposicoes == nComposicoes);
	}
	
	
	 
	public static void main(String[] args){

		Ferrovia ferrovia = Ferrovia.getInstance();
		ferrovia.defineCenario(1);
		ferrovia.registraTratadorDeEventos(CControle.getControle());
		
		String [] elementos = ferrovia.consultaElementos();
		CControle.getControle().inicializarMalha(elementos);
		
		String id = (String) CControle.getControle().getMalha().getTrechos().keySet().toArray()[0];
		CTrecho test = (CTrecho) CControle.getControle().getMalha().getTrechos().get(id);
		
		System.out.println("end");
	}
}
